#ifndef __MPEGTS_STUFF
#define __MPEGTS_STUFF

/*
 *   This file is part of ed_pvr.
 *
 *   ed_pvr is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   ed_pvr is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with ed_pvr.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef __cplusplus
    extern "C" {
#endif

#include <stdint.h>
#include "bitstream.h"
//#include "utils2.h"

#define CLOCK_90K                       90000.0
#define CLOCK_27M                       27000000.0
#define CLOCK_CONV                      (double)(CLOCK_27M/CLOCK_90K)

#define MPEGTS_VIDEO_STREAM_START       0xE0
#define MPEGTS_VIDEO_STREAM_END         0xEF
#define MPEGTS_AUDIO_STREAM_START       0xC0
#define MPEGTS_AUDIO_STREAM_END         0xDF
#define MPEGTS_PROGRAM_END              0xB9
#define MPEGTS_PACK_HEADER              0xBA
#define MPEGTS_SYSTEM_HEADER            0xBB
#define MPEGTS_PROGRAM_STREAM           0xBC
#define MPEGTS_PRIVATE_STREAM1          0xBD
#define MPEGTS_PADDING_STREAM           0xBE
#define MPEGTS_PRIVATE_STREAM2          0xBF
#define MPEGTS_ECM_STREAM               0xF0
#define MPEGTS_EMM_STREAM               0xF1

#define TS_SYNC_BYTE                    0x47
#define TS_UNIT_START                   0x40
#define TS_UNIT_PAYLOAD_ONLY            0x10
#define TS_UNIT_PAYLOAD_AF              0x30

#define TS_PACKET_SIZE                  188
#define TS_HEADER_LEN                   4

#define PAT_PID                         0x00
#define CA_PID                          0x01
#define DST_PID                         0x02
#define IPMP_PID                        0x03
#define PMT_PID                         0x1E0
#define NULL_PID                        0x1FFF
#define EIT_PID                         0x12

#define TID_PAT                         0x00
#define TID_CA                          0x01
#define TID_PMT                         0x02
#define TID_DES                         0x03
#define TID_14496_SDC                   0x04
#define TID_14496_ODC                   0x05
#define TID_META                        0x06
#define TID_IPMP                        0x07
#define TID_RESERVED_START              0x08
#define TID_RESERVED_END                0x3F
#define TID_USER_START                  0x40
#define TID_USER_END                    0xFE
#define TID_FORBIDDEN                   0xFF

#define ADAPT_RESERVED                  0x00
#define ADAPT_NO_FIELD_ONLY_PAYLOAD     0x01
#define ADAPT_FIELD_ONLY_NO_PAYLOAD     0x02
#define ADAPT_FIELD_AND_PAYLOAD         0x03

#define NO_PTS                          0x00
#define PTS_ONLY                        0x02
#define PTS_AND_DTS                     0x03

#define AF_DISCONTINUITY                0x80
#define AF_RANDOM_ACCESS                0x50
#define AF_PCR                          0x10
#define AF_ES_PRI                       0x20

#define MPEGTS_STUFF_BYTE               0xFF

#define CRC_LENGTH                      4  //CRC = 4 bytes

#define PAT_PROGRAM_LENGTH              4  // program_number = 2 bytes
                                           // reserved(3bit)+ [program_map_id or network_id](13bits) = 2 bytes

#define PAT_BYTES_AFTER_SECTION_LEN     5  // ts_id = 2 bytes
                                           // resevred(2bit)+version(5bit)+current_next_indicator(1bit) = 1 byte
                                           // section number = 1 byte
                                           // last section number = 1 byte

#define PMT_BYTES_AFTER_SECTION_LEN     9  // program_number = 2 bytes
                                           // resevred(2bit)+version(5bit)+current_next_indicator(1bit) = 1 byte
                                           // section number = 1 byte
                                           // last section number = 1 byte
                                           // reserved(3bits) + PCR PID(13) = 2 bytes
                                           // reserved(4bits) + program_info_length(12) = 2 bytes

#define PMT_PROGRAM_LENGTH              5  // stream_type =  1 byte
                                           // reserved(3bit) + elementary_pid(13bits) = 2 bytes
                                           // reserved(4bit) + es_info_length(12bits) = 2 bytes


#define PAT_CONST_LENGTH					(3+PAT_BYTES_AFTER_SECTION_LEN)
#define PMT_CONST_LENGTH					(3+PMT_BYTES_AFTER_SECTION_LEN)

/*

#define MPEGTS_STREAM_TYPE_ISO13818_V		0x02  // VIDEO
#define MPEGTS_STREAM_TYPE_ISO11172_A		0x03  // AUDIO
#define MPEGTS_STREAM_TYPE_ISO13818_3		0x04  // AUDIO
#define MPEGTS_STREAM_TYPE_ISO14496_10		0x1B
#define MPEGTS_STREAM_TYPE_USER_DATA		0x81
*/
#define MPEGTS_STREAM_TYPE_RESERVED             0x00  // Reserved
#define MPEGTS_STREAM_TYPE_ISO11172_V           0x01  // ISO/IEC 11172 Video
#define MPEGTS_STREAM_TYPE_ISO13818_V           0x02  // VIDEO
#define MPEGTS_STREAM_TYPE_ISO11172_A           0x03  // AUDIO
#define MPEGTS_STREAM_TYPE_ISO13818_3           0x04  // AUDIO
#define MPEGTS_STREAM_TYPE_ISO13818_1_P_SECT    0x05
#define MPEGTS_STREAM_TYPE_ISO13818_1_PES       0x06
#define MPEGTS_STREAM_TYPE_ISO13522             0x07
#define MPEGTS_STREAM_TYPE_ISO13818_DSM_CC      0x08
#define MPEGTS_STREAM_TYPE_ITU_H222_1           0x09
#define MPEGTS_STREAM_TYPE_ISO13818_6_A         0x0A
#define MPEGTS_STREAM_TYPE_ISO13818_6_B         0x0B
#define MPEGTS_STREAM_TYPE_ISO13818_6_C         0x0C
#define MPEGTS_STREAM_TYPE_ISO13818_6_D         0x0D
#define MPEGTS_STREAM_TYPE_ISO13818_1_AUX       0x0E
#define MPEGTS_STREAM_TYPE_ISO13818_7           0x0F
#define MPEGTS_STREAM_TYPE_ISO14492_2           0x10
#define MPEGTS_STREAM_TYPE_ISO14492_3           0x11
#define MPEGTS_STREAM_TYPE_ISO14492_1_PES       0x12
#define MPEGTS_STREAM_TYPE_ISO14492_1_SEC       0x13
#define MPEGTS_STREAM_TYPE_ISO13818_6_SYNC      0x14
#define MPEGTS_STREAM_TYPE_META_IN_PES          0x15
#define MPEGTS_STREAM_TYPE_META_IN_SEC          0x16
#define MPEGTS_STREAM_TYPE_ISO13818_META_IN_DC  0x17
#define MPEGTS_STREAM_TYPE_ISO13818_META_IN_OC  0x18
#define MPEGTS_STREAM_TYPE_ISO13818_META_SYNC   0x19
#define MPEGTS_STREAM_TYPE_IPMP                 0x1A
#define MPEGTS_STREAM_TYPE_ISO14496_10          0x1B
#define MPEGTS_STREAM_TYPE_SOMETHING			0x80
#define MPEGTS_STREAM_TYPE_USER_DATA            0x81
#define MPEGTS_STREAM_TYPE_SCTE35				0x86


#define MPEGTS_TYPE_UNHANDLED           0
#define MPEGTS_TYPE_VIDEO               1
#define MPEGTS_TYPE_AUDIO               2
#define MPEGTS_TYPE_PAT                 3
#define MPEGTS_TYPE_PMT                 4
#define MPEGTS_TYPE_INVALID             -1

#define MPEGTS_PMT_DESC_VIDEO			0x02
#define MPEGTS_PMT_DESC_AUDIO			0x03
#define MPEGTS_PMT_DESC_REG				0x05
#define MPEGTS_PMT_DESC_DSALIGN			0x06
#define MPEGTS_PMT_DESC_CA				0x09
#define MPEGTS_PMT_DESC_ISO639_LANG		0x0A
#define MPEGTS_PMT_DESC_SMOOTH			0x10
#define MPEGTS_PMT_DESC_STD				0x11
#define MPEGTS_PMT_DESC_MP4_VIDEO		0x1B
#define MPEGTS_PMT_DESC_MP4_AUDIO		0x1C
#define MPEGTS_PMT_DESC_AVC_VIDEO		0x28
#define MPEGTS_PMT_DESC_AAC_AUDIO		0x2B
#define MPEGTS_PMT_DESC_STUFFING		0x80
#define MPEGTS_PMT_DESC_AC3				0x81
#define MPEGTS_PMT_DESC_CAPTION			0x86
#define MPEGTS_PMT_DESC_CONT_ADV		0x87
#define MPEGTS_PMT_DESC_EXT_CHAN_NAME	0xA0
#define MPEGTS_PMT_DESC_SERV_LOC		0xA1
#define MPEGTS_PMT_DESC_TIME_SHIFTED	0xA2
#define MPEGTS_PMT_DESC_COMP_NAME		0xA3

static const uint8_t MPEGTS_PMT_AC3_REG[4] = {0x41, 0x43, 0x2d, 0x33};

static const uint8_t TS_NULL_PACKET[188] =
{
	0x47, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
};
/*
static const char *MPEG2_PIC_TYPE[5]=
{
	"Undefined",
	"I-Frame",
	"P-Frame",
	"B-Frame",
	"D-Frame",
};
*/
struct mpegts_pat_program_struct
{
	uint16_t program_number;
	uint8_t reserved;
	uint16_t pid;
//        uint16_t network_pid;
//        uint16_t program_pid;
	struct mpegts_pat_program_struct *next;
};
typedef struct mpegts_pat_program_struct MPEGTS_PAT_PROGRAM_STRUCT;

struct mpegts_pat_struct
{
	uint8_t table_id;
	uint8_t section_syntax_indicator;
	uint8_t zero;
	uint8_t reserved1;
	uint16_t section_length;
	uint16_t transport_stream_id;
	uint8_t reserved2;
	uint8_t version_number;
	uint8_t current_next_indicator;
	uint8_t section_number;
	uint8_t last_section_number;
	uint32_t crc;

	uint16_t program_count;
	MPEGTS_PAT_PROGRAM_STRUCT * first_program;
	MPEGTS_PAT_PROGRAM_STRUCT * current_program;
	uint16_t program_num_filter;
};
typedef struct mpegts_pat_struct MPEGTS_PAT;

struct mpegts_map_es_struct
{
	uint8_t stream_type; //8
	uint8_t reserved1; //3
	uint16_t pid; //13
	uint8_t reserved2; //4
	uint16_t info_len; //12
	uint8_t * descriptor;
	struct mpegts_map_es_struct *next;
};
typedef struct mpegts_map_es_struct MPEGTS_MAP_ES;

struct mpegts_pmt_struct
{
	uint8_t table_id;  // 8 bits
	uint8_t section_syntax_indicator; //1
	uint8_t zero; //1
	uint8_t reserved1; //2
	uint16_t section_length; //12
	uint16_t program_number; //16
	uint8_t reserved2; //2
	uint8_t version_number; //5
	uint8_t current_next_indicator; //1
	uint8_t section_number; //8
	uint8_t last_section_number; //8
	uint8_t reserved3; //3
	uint16_t pcr_pid; //13
	uint8_t reserved4;  //4
	uint16_t program_info_length; //12
	uint8_t *program_info_data;


	uint16_t es_count;
	MPEGTS_MAP_ES * first_es;
	MPEGTS_MAP_ES * current_es;
	uint32_t crc; //32
};
typedef struct mpegts_pmt_struct MPEGTS_PMT;

struct mpegts_payload_start_struct
{
//	uint8_t  start;  // Where in the packet does the payload start?
//	uint32_t packet_num;

	uint32_t start_code;
	uint8_t stream_id;
	uint16_t len;
	uint8_t one_zero;
	uint8_t pes_scrambling;
	uint8_t pes_priority;
	uint8_t data_alignment;
	uint8_t copyright;
	uint8_t original;  //1 = org, 0 = copy
	uint8_t pts_dts_flag;
	uint8_t escr_flag;
	uint8_t es_rate_flag;
	uint8_t dsm_trick_mode_flag;
	uint8_t additional_copy_info_flag;
	uint8_t pes_crc_flag;
	uint8_t pes_extension_flag;
	uint8_t pes_header_data_len;
	uint64_t pts;
	uint64_t dts;

//	uint64_t new_pts;
//	uint64_t new_dts;

	MPEGTS_MAP_ES map;
	uint8_t * extra_data;
};
typedef struct mpegts_payload_start_struct MPEGTS_PAYLOAD_START;

struct mpegts_section
{
	uint8_t table_id;
	uint8_t section_syntax_indicator;
	uint16_t ts_id;
	uint8_t version_number;
	uint8_t current_next_indicator;
	uint8_t section_number;
	uint8_t last_section_number;

	uint8_t *section_data;
	uint16_t section_len;

	void * extra_data;
};
typedef struct mpegts_section MPEGTS_SECTION;

struct mpegts_adaptfield_struct
{
	uint8_t adaptation_field_length;
	uint8_t discontinuity;
	uint8_t random_access;
	uint8_t es_prio;
	uint8_t pcr_flag;
	uint8_t opcr_flag;
	uint8_t splice_flag;
	uint8_t ts_private_flag;
	uint8_t field_ext_flag;
	uint64_t pcr_baseH;
	uint64_t pcr_base;
	uint8_t pcr_reserved;
	uint16_t pcr_ext;

	uint8_t stuffing_bytes;
	uint64_t pcr_27khz;

	uint64_t opcr_base;
	uint8_t opcr_reserved;
	uint16_t opcr_ext;

	uint8_t transport_private_data_length;
	uint8_t * transport_private_data;

	/* add other adapatation field flags */
};
typedef struct mpegts_adaptfield_struct MPEGTS_ADAPTATION_FIELD;

struct mpegts_packet_struct
{
	uint8_t sync_byte;
	uint8_t ts_error;               // 1
	uint8_t payload_start;  // 1
	uint8_t ts_priority;    // 1
	uint16_t pid;           // 13
	uint8_t ts_scrambling;  // 2
	uint8_t adapt_field_control;    // 2
	uint8_t cont_counter;   // 4
	uint8_t pointer_field;
	uint8_t transport_private_data_length;
	uint8_t splice_countdown;
	void * extra_data;

	MPEGTS_ADAPTATION_FIELD * adaptation_field;
	MPEGTS_PAYLOAD_START * payload_start_struct;

	BITSTREAM *bitstream;

	uint8_t * packet_data;
	uint8_t packet_data_size;

	uint8_t type;
	uint8_t frame_type;
//	uint8_t pmt_descriptor;
//	uint16_t pmt_pid;
//	MPEGTS_PAT *pat;
//	MPEGTS_PMT *pmt;
};
typedef struct mpegts_packet_struct MPEGTS_PACKET;



struct mpegts_newpat_struct
{
	uint16_t program_num;
	uint16_t pmt_pid;
	uint16_t ts_id;
	uint8_t version;
	uint8_t counter;
	uint8_t new_pat_data[TS_PACKET_SIZE];
	uint8_t *ts_header;
		uint8_t ts_header_len;
};
typedef struct mpegts_newpat_struct MPEGTS_NEWPAT_STRUCT;

struct mpegts_newpmt_struct
{
	uint16_t program_number;
	uint16_t pcr_pid;
	uint8_t *program_descriptor;
	uint16_t program_descriptor_len;
	uint8_t counter;
	uint8_t new_pmt_data[TS_PACKET_SIZE];
	uint8_t *ts_header;
	uint8_t ts_header_len;
	MPEGTS_MAP_ES * desc_es;

};
typedef struct mpegts_newpmt_struct MPEGTS_NEWPMT_STRUCT;

struct mpegts_pts_dts_restamp
{
	uint8_t stamp_failed;
	uint64_t org_pts;
	uint64_t org_dts;
	uint64_t pts;
	uint64_t dts;
};
typedef struct mpegts_pts_dts_restamp MPEGTS_PTS_DTS_RESTAMP;



struct mpegts_parse_struct
{
	uint64_t packet_count;
	uint64_t video_frame_count;
	uint64_t audio_frame_count;
	uint16_t pmt_pid;
	uint8_t stream_type;
	uint8_t frame_type;
	uint8_t pmt_type;
	uint64_t program_number;

	MPEGTS_PAT *pat;
	MPEGTS_PMT *pmt;
};
typedef struct mpegts_parse_struct MPEGTS_PARSE_STRUCT;



// -----------------------------------------------------------

void mpegts_print_adaptation_field(MPEGTS_ADAPTATION_FIELD *);
void mpegts_print_pat(MPEGTS_PAT *);
void mpegts_print_pmt(MPEGTS_PMT *);

MPEGTS_PACKET * mpegts_parse_packet(BITSTREAM *);
MPEGTS_PACKET * mpegts_parse_packet2(BITSTREAM *, MPEGTS_PARSE_STRUCT*);
//MPEGTS_PAYLOAD_START * mpegts_parse_payload_start(BITSTREAM *, MPEGTS_PARSE_STRUCT*);
MPEGTS_PAYLOAD_START * mpegts_parse_payload_start(BITSTREAM *);
MPEGTS_ADAPTATION_FIELD * mpegts_parse_adaptation_field(BITSTREAM *);
MPEGTS_PAT * mpegts_parse_pat(BITSTREAM *);
MPEGTS_PAT *mpegts_dup_pat(MPEGTS_PAT *);
MPEGTS_PMT * mpegts_parse_pmt(BITSTREAM *, uint8_t);

void mpegts_free_pat(MPEGTS_PAT *);
void mpegts_free_pmt(MPEGTS_PMT *);
void mpegts_free_packet(MPEGTS_PACKET *);

uint64_t mpegts_parse_pts(BITSTREAM *);
uint8_t mpegts_fix_pat(uint8_t *, uint32_t, uint16_t, uint16_t);
uint8_t mpegts_fix_pmt(uint8_t *data, uint32_t len,  uint16_t, uint16_t, MPEGTS_MAP_ES *);
MPEGTS_PTS_DTS_RESTAMP * mpegts_offset_pts_dts(uint8_t *, uint32_t, uint64_t, uint16_t);

uint8_t mpegts_streamtype_valid(uint8_t);
//int32_t mpegts_need_sync(uint8_t *, uint32_t);


#ifdef __cplusplus
    }
#endif

#endif
